package com.jeefw.cloud.httpdoc.utils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.JAXBException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.poi.hwpf.HWPFDocumentCore;
import org.apache.poi.hwpf.converter.WordToHtmlConverter;
import org.apache.poi.hwpf.converter.WordToHtmlUtils;
import org.docx4j.Docx4J;
import org.docx4j.Docx4jProperties;
import org.docx4j.TraversalUtil;
import org.docx4j.XmlUtils;
import org.docx4j.convert.in.xhtml.XHTMLImporterImpl;
import org.docx4j.convert.out.ConversionFeatures;
import org.docx4j.convert.out.HTMLSettings;
import org.docx4j.convert.out.html.SdtToListSdtTagHandler;
import org.docx4j.convert.out.html.SdtWriter;
import org.docx4j.finders.SectPrFinder;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.AltChunkType;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.openpackaging.parts.relationships.Namespaces;
import org.docx4j.relationships.Relationship;
import org.docx4j.wml.Body;
import org.docx4j.wml.ContentAccessor;
import org.docx4j.wml.P;
import org.docx4j.wml.PPr;
import org.docx4j.wml.RFonts;
import org.docx4j.wml.RPr;
import org.docx4j.wml.SectPr;
import org.docx4j.wml.Text;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Entities;
import org.jvnet.jaxb2_commons.ppp.Child;
import org.springframework.web.util.HtmlUtils;

import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateNotFoundException;

public class DocConverterUtils {
	private static Mapper fontMapper = null;
	private static String htmlUserCss = "html, body, div, span, h1, h2, h3, h4, h5, h6, p, a, img,  ol, ul, li, table, caption, tbody, tfoot, thead, tr, th, td "
			+ "{ margin: 0; padding: 0; border: 0;}\nbody {line-height: 1;} ";
	private static final String[] fontLocales = { "隶书|LiSu", "宋体|SimSun",
			"微软雅黑|Microsoft YaHei", "黑体|SimHei", "楷体|KaiTi", "新宋体|NSimSun",
			"华文行楷|STXingkai", "华文仿宋|STFangsong", "宋体扩展|simsun-extB",
			"仿宋|FangSong", "仿宋_GB2312|FangSong_GB2312", "幼圆|YouYuan",
			"华文宋体|STSong", "华文中宋|STZhongsong", "楷体_GB2312|KaiTi_GB2312" };

	private static Charset utf8 = Charset.forName("UTF-8");

	/**
	 * 
	 * @描述：配置中文字体
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午2:57:37
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param wordMLPackage
	 * @throws Exception
	 */
	private static void configSimSunFont(WordprocessingMLPackage wordMLPackage)
			throws Exception {
		if (BlankUtils.isBlank(fontMapper)) {
			fontMapper = new IdentityPlusMapper();
		}
		ChineseFont[] fonts = ChineseFont.values();
		for (ChineseFont font : fonts) {
			// 加载字体文件（解决linux环境下无中文字体问题）
			if (BlankUtils.isBlank(fontMapper.get(font.getFontName()))) {
				PhysicalFonts.addPhysicalFonts(font.getFontName(),
						font.getFontUrl());
				PhysicalFont simsunFont = PhysicalFonts.get(font.getFontName());
				fontMapper.put(font.getFontName(), simsunFont);
			}
		}

		for (int i = 0, iLen = fontLocales.length; i < iLen; i++) {
			String[] localeNames = StringUtils.split(fontLocales[i], "|");
			if ((localeNames.length > 1)
					&& BlankUtils.isBlank(fontMapper.get(localeNames[0]))) {
				fontMapper.put(localeNames[0],
						PhysicalFonts.get(localeNames[1]));
			}
		}

		wordMLPackage.setFontMapper(fontMapper);
		String defaultFontName = ChineseFont.SIMSUM.getFontName();
		if (StringUtils.isNotEmpty(defaultFontName)) {
			RPr rpr = wordMLPackage.getMainDocumentPart().getPropertyResolver()
					.getDocumentDefaultRPr();
			PhysicalFont asciiFont = StringUtils.isNotEmpty(rpr.getRFonts()
					.getAscii()) ? fontMapper.get(rpr.getRFonts().getAscii())
					: null;
			if ((BlankUtils.isBlank(asciiFont))
					|| (!defaultFontName.equalsIgnoreCase(asciiFont.getName()))) {
				// 设置文件默认字体
				RFonts rfonts = Context.getWmlObjectFactory().createRFonts();
				rfonts.setAsciiTheme(null);
				rfonts.setAscii(ChineseFont.SIMSUM.getFontName());
				rfonts.setHAnsi(ChineseFont.SIMSUM.getFontName());
				rfonts.setEastAsia(ChineseFont.SIMSUM.getFontName());

				rpr.setRFonts(rfonts);
			}
		}

		/*
		 * //设置默认行间距 PPr ppr =
		 * wordMLPackage.getMainDocumentPart().getPropertyResolver()
		 * .getDocumentDefaultPPr(); Spacing spacing = ppr.getSpacing(); if
		 * (spacing == null) { spacing = new Spacing(); ppr.setSpacing(spacing);
		 * } spacing.setLine(new BigInteger("400"));
		 * spacing.setLineRule(STLineSpacingRule.EXACT);
		 * spacing.setBeforeLines(new BigInteger("0"));
		 * spacing.setAfterLines(new BigInteger("0"));
		 * System.out.println(spacing);
		 */
	}

	/**
	 * 
	 * @描述：查找文档中富文本标记
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午2:57:48
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param richTextMap
	 * @param object
	 * @param accessor
	 */
	private static void findRichTextNode(Map<String, List<Object>> richTextMap,
			Object object, ContentAccessor accessor) {
		Object textObj = XmlUtils.unwrap(object);
		if (textObj instanceof Text) {
			String text = ((Text) textObj).getValue();
			if (StringUtils.isNotEmpty(text)) {
				text = text.trim();
				if (text.startsWith("$RH{") && text.endsWith("}")) {
					String textTag = text.substring("$RH{".length(),
							text.length() - 1);
					if (StringUtils.isNotEmpty(textTag) && (accessor != null)) {
						if (richTextMap.containsKey(textTag)) {
							richTextMap.get(textTag).add(accessor);
						} else {
							List<Object> objList = new ArrayList<Object>();
							objList.add(accessor);
							richTextMap.put(textTag, objList);

						}
					}
				}
			}
		} else if (object instanceof ContentAccessor) {
			List<Object> objList = ((ContentAccessor) object).getContent();
			for (int i = 0, iSize = objList.size(); i < iSize; i++) {
				findRichTextNode(richTextMap, objList.get(i),
						(ContentAccessor) object);
			}
		}
	}

	/**
	 * 
	 * @描述：将Html内容转为Word支持的Chunk对象
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午3:00:17
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param wordMLPackage
	 * @param content
	 * @return
	 * @throws Docx4JException
	 * @throws JAXBException
	 */
	private static List<Object> convertToAltChunk(
			WordprocessingMLPackage wordMLPackage, String content)
			throws Docx4JException, JAXBException {
		MainDocumentPart document = wordMLPackage.getMainDocumentPart();

		List<Object> wmlObjList = null;
		Body templateBody = document.getContents().getBody();
		try {
			document.getContents().setBody(XmlUtils.deepCopy(templateBody));
			document.getContent().clear();

			// 处理半角空格：&ensp; 为 &#8194;
			String contentHtml = (content == null) ? "" : content
					.replaceAll("((&ensp;)+)",
							"<span style=\"white-space:pre;\">$1</span>")
					.replaceAll("&ensp;", "&enspTempMark;");

			Document doc = Jsoup.parse(contentHtml);
			doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml)
					.escapeMode(Entities.EscapeMode.xhtml);

			// 处理半角空格，确保半角空格在word中正常输出;
			contentHtml = doc.html().replaceAll("&amp;enspTempMark;", " ");

			document.addAltChunk(AltChunkType.Xhtml, contentHtml.getBytes(utf8));
			wmlObjList = document.getContent();
		} finally {
			document.getContents().setBody(templateBody);
		}
		return wmlObjList;
	}

	/**
	 * 
	 * @描述：获取Wml对象中的Ppr对象
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午3:01:00
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param object
	 * @return
	 */
	private static PPr getWmlObjectPpr(Object object) {
		if (object == null) {
			return null;
		} else if (object instanceof P) {
			return ((P) object).getPPr();
		} else if (object instanceof Child) {
			return getWmlObjectPpr(((Child) object).getParent());
		} else {
			return null;
		}
		// XmlUtils.marshaltoString(object)
		// Context.getWmlObjectFactory().
		// ((CTAltChunk)object).getAltChunkPr().g
	}

	/**
	 * 
	 * @描述：拷贝相关格式设置对wml对象中
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午3:01:50
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param source
	 * @param targetList
	 */
	private static void setWmlPprSetting(Object source, List<Object> targetList) {
		PPr sourcePpr = getWmlObjectPpr(source);
		if (sourcePpr != null) {
			for (int i = 0, iSize = targetList.size(); i < iSize; i++) {
				PPr ppr = getWmlObjectPpr(targetList.get(i));
				if (ppr != null) {
					ppr.setInd(sourcePpr.getInd());
					ppr.setSpacing(sourcePpr.getSpacing());
				}
			}
		}
		// sourcePpr.getSpacing()
	}

	/**
	 * 
	 * @描述：获取Freemarker配置
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午3:03:06
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @return
	 * @throws IOException
	 */
	private static Configuration getFreemarkerConfig() throws IOException {
		Configuration config = new Configuration(
				Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
		config.setEncoding(Locale.CHINA, "utf-8");
		return config;
	}

	/**
	 * 
	 * @描述：合并填充模板数据
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午3:06:15
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param templateFile
	 * @param data
	 * @return
	 * @throws TemplateNotFoundException
	 * @throws MalformedTemplateNameException
	 * @throws ParseException
	 * @throws IOException
	 * @throws TemplateException
	 * @throws Docx4JException
	 */
	public static WordprocessingMLPackage mergeTemplateFile(File templateFile,
			Map<String, Object> data) throws TemplateNotFoundException,
			MalformedTemplateNameException, ParseException, IOException,
			TemplateException, Docx4JException {

		Configuration config = getFreemarkerConfig();
		config.setDirectoryForTemplateLoading(templateFile.getParentFile());
		// 模版文件名
		Template template = config.getTemplate(templateFile.getName());
		template.setOutputEncoding("UTF-8");
		StringWriter writer = new StringWriter();
		template.process(data, writer);
		writer.flush();
		String xmlString = writer.toString();

		InputStream in = IOUtils.toByteArrayInputStream(xmlString);
		WordprocessingMLPackage wordMlPackage = WordprocessingMLPackage
				.load(in);
		return wordMlPackage;
	}

	/**
	 * 
	 * @描述：用Html的Chunk替换模板中的富文本标记
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午2:58:56
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param wordMLPackage
	 * @param richTextMap
	 * @throws Exception
	 */
	public static void replaceRichText(WordprocessingMLPackage wordMLPackage,
			Map<String, String> richTextMap) throws Exception {
		configSimSunFont(wordMLPackage);
		MainDocumentPart document = wordMLPackage.getMainDocumentPart();
		Map<String, List<Object>> textNodeMap = new HashMap<String, List<Object>>();
		findRichTextNode(textNodeMap, document.getContents().getBody(), null);
		Iterator<String> iterator = richTextMap.keySet().iterator();
		while (iterator.hasNext()) {
			String textTag = iterator.next();
			List<Object> textNodeList = textNodeMap.get(textTag);
			if (CollectionUtils.isNotEmpty(textNodeList)
					&& richTextMap.containsKey(textTag)) {
				List<Object> textObjList = convertToAltChunk(wordMLPackage,
						richTextMap.get(textTag));
				for (int i = 0, iSize = textNodeList.size(); i < iSize; i++) {
					if (!BlankUtils.isBlank(textNodeList.get(i))) {
						// setWmlPprSetting(textNodeList.get(i), textObjList);
						TraversalUtil.replaceChildren(textNodeList.get(i),
								textObjList);
					}
				}
			}
		}
	}

	private static void deleteErrorCode(Object part, String... errCodes) {
		if (ArrayUtils.isNotEmpty(errCodes)) {
			Object textPart = XmlUtils.unwrap(part);
			if (textPart instanceof Text) {
				String partText = ((Text) textPart).getValue();
				for (int i = 0, iLen = errCodes.length; i < iLen; i++) {
					partText = partText.replace(errCodes[i], "");
				}
				((Text) textPart).setValue(partText);
			} else if (part instanceof ContentAccessor) {
				List<Object> partList = ((ContentAccessor) part).getContent();
				for (int i = 0, iSize = partList.size(); i < iSize; i++) {
					deleteErrorCode(partList.get(i), errCodes);
				}
			}
		}
	}

	/**
	 * 
	 * @描述：将Doc文件转Docx文件
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午3:05:42
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param docFile
	 * @param docxFile
	 * @return
	 * @throws Exception
	 */
	public static void convertDocToDocx(File docFile, File docxFile)
			throws Exception {
		String docHtml = replaceHtmlStyle(convertDocToHtml(docFile));

		WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
				.createPackage();

		Document doc = Jsoup.parse(docHtml);
		// 转为 xhtml 格式
		doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml)
				.escapeMode(Entities.EscapeMode.xhtml);
		// 配置中文字体
		configSimSunFont(wordMLPackage);
		XHTMLImporterImpl xhtmlImporter = new XHTMLImporterImpl(wordMLPackage);

		// 导入 xhtml
		wordMLPackage.getMainDocumentPart().getContent()
				.addAll(xhtmlImporter.convert(doc.html(), doc.baseUri()));

		wordMLPackage.save(docxFile);
	}

	/**
	 * 
	 * @描述：将Doc文件转换为Html字符串
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午3:03:25
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param docFile
	 * @throws Exception
	 */
	public static String convertDocToHtml(File docFile) throws Exception {
		final HWPFDocumentCore hwpfDocument = WordToHtmlUtils.loadDoc(docFile);
		WordToHtmlConverter converter = new WordToHtmlConverter(
				DocumentBuilderFactory.newInstance().newDocumentBuilder()
						.newDocument());
		converter.processDocument(hwpfDocument);

		DOMSource domSource = new DOMSource(converter.getDocument());
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer serializer = tf.newTransformer();

		// TODO set encoding from a command argument
		serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
		serializer.setOutputProperty(OutputKeys.INDENT, "yes");
		serializer.setOutputProperty(OutputKeys.METHOD, "html");

		ByteArrayOutputStream out = new ByteArrayOutputStream();
		try {
			serializer.transform(domSource, new StreamResult(out));
			return out.toString("UTF-8");
		} finally {
			IOUtils.closeQuietly(out);
		}
	}

	/**
	 * 
	 * @描述：docx4j方式将wml转为html
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月21日下午3:44:58
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param wmlPackage
	 * @param out
	 * @throws Exception
	 */
	public static String convertDocxToHtml(File docxFile) throws Exception {
		WordprocessingMLPackage wmlPackage = WordprocessingMLPackage
				.load(docxFile);
		List<Object> partList = wmlPackage.getMainDocumentPart().getContents()
				.getBody().getContent();
		for (int i = 0, iSize = partList.size(); i < iSize; i++) {
			deleteErrorCode(partList.get(i), new String(new byte[] { -30, -128,
					-117 }));
		}
		// 删除页眉页脚
		DocConverterUtils.deleteHeaderFooter(wmlPackage);
		// 删除“二、教学目标”之前的内容
		// DocConverterUtils.deleteWordMLPart(wmlPackage, null, "二、教学目标");

		configSimSunFont(wmlPackage);
		HTMLSettings htmlSettings = Docx4J.createHTMLSettings();
		// htmlSettings.setImageDirPath(root + "images");
		// htmlSettings.setImageTargetUri("images");
		htmlSettings.setWmlPackage(wmlPackage);

		htmlSettings.setUserCSS(htmlUserCss);
		htmlSettings.setFontMapper(fontMapper);
		htmlSettings.setUserBodyTop("");
		htmlSettings.setUserBodyTail("");
		htmlSettings.setFontFamilyStack(true);
		Docx4jProperties.setProperty("docx4j.Convert.Out.HTML.OutputMethodXML",
				true);
		Docx4jProperties.getProperties().setProperty(
				"docx4j.Log4j.Configurator.disabled", "true");
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		try {
			SdtWriter.registerTagHandler("HTML_ELEMENT",
					new SdtToListSdtTagHandler());
			htmlSettings.getFeatures().remove(
					ConversionFeatures.PP_HTML_COLLECT_LISTS);
			Docx4J.toHTML(htmlSettings, out, Docx4J.FLAG_EXPORT_PREFER_XSL);
			return out.toString("UTF-8");
		} finally {
			IOUtils.closeQuietly(out);
		}
	}

	/**
	 * 
	 * @描述：删除doc文档的页眉页脚
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月24日下午1:50:14
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param wmlPackage
	 */
	private static void deleteHeaderFooter(WordprocessingMLPackage wmlPackage) {
		MainDocumentPart mdp = wmlPackage.getMainDocumentPart();

		// Remove from sectPr
		SectPrFinder finder = new SectPrFinder(mdp);
		new TraversalUtil(mdp.getContent(), finder);
		for (SectPr sectPr : finder.getOrderedSectPrList()) {
			sectPr.getEGHdrFtrReferences().clear();
		}

		List<Relationship> hfRels = new ArrayList<Relationship>();
		for (Relationship rel : mdp.getRelationshipsPart().getRelationships()
				.getRelationship()) {

			if (rel.getType().equals(Namespaces.HEADER)
					|| rel.getType().equals(Namespaces.FOOTER)) {
				hfRels.add(rel);
			}
		}
		for (Relationship rel : hfRels) {
			mdp.getRelationshipsPart().removeRelationship(rel);
		}
	}

	/**
	 * 
	 * @描述：将html的style字符串解析成样式Map
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月24日下午7:22:49
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param cssStyle
	 * @return
	 */
	private static Map<String, String> parseCssStyle(String cssStyle) {
		if (StringUtils.isEmpty(cssStyle)) {
			return null;
		}
		HashMap<String, String> cssMap = new HashMap<String, String>();
		String[] cssStyles = cssStyle.split(";");
		for (int i = 0, iSize = cssStyles.length; i < iSize; i++) {
			if (StringUtils.isNotEmpty(cssStyles[i])
					&& (cssStyles[i].split(":").length > 1)) {
				String[] cssValues = cssStyles[i].split(":");
				cssMap.put(cssValues[0], cssValues[1]);
			}
		}
		return cssMap;
	}

	/**
	 * 
	 * @描述：将Class样式增加到html的style属性中
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月24日下午7:23:21
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param cssStyle
	 * @param classes
	 * @param classMap
	 * @return
	 */
	private static String parseCssStyle(String cssStyle, String[] classes,
			Map<String, String> classMap) {
		StringBuffer newStyle = new StringBuffer();
		if (StringUtils.isNotEmpty(cssStyle)) {
			newStyle.append(cssStyle);
			if (!cssStyle.endsWith(";")) {
				newStyle.append(";");
			}
		}

		try {
			for (int i = 0, iSize = classes.length; i < iSize; i++) {
				String className = classes[i].trim();
				if (StringUtils.isNotEmpty(className)) {
					Map<String, String> styleMap = parseCssStyle(classMap
							.get(className));
					if ((styleMap != null) && (styleMap.size() > 0)) {
						Iterator<String> iterator = styleMap.keySet()
								.iterator();
						while (iterator.hasNext()) {
							String name = iterator.next();
							String value = styleMap.get(name);
							if (StringUtils.isNoneEmpty(name)
									&& StringUtils.isNotEmpty(value)
									&& (newStyle.toString().indexOf(name) == -1)) {
								newStyle.append(name).append(":").append(value)
										.append(";");
							}
						}
					}
				}
			}
		} catch (Exception ex) {
		}

		String resultStyle = newStyle.toString();
		resultStyle = resultStyle.replace("white-space:pre-wrap", "").replace(
				"background-color: #FFFFFF;", "");
		return resultStyle;
	}

	private static void addHtmlCssStyle(Map<String, String> styleMap,
			String cssName, String cssValue) {
		if (styleMap == null) {
			styleMap = new HashMap<String, String>();
		}
		if (StringUtils.isNotEmpty(cssName) && StringUtils.isNotEmpty(cssValue)) {
			String[] cssNames = cssName.split(",");
			for (int i = 0, iLen = cssNames.length; i < iLen; i++) {
				String cName = cssNames[i].trim();
				if (StringUtils.isNotEmpty(cName)) {
					if (StringUtils.isEmpty(styleMap.get(cName))) {
						styleMap.put(cName, cssValue);
					} else {
						styleMap.put(cName, styleMap.get(cName) + ";"
								+ cssValue);
					}
				}
			}
		}
	}

	/**
	 * 
	 * @描述：解析用户css样式
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月26日下午12:43:22
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @return
	 */
	private static void addHtmlUserCss(Map<String, String> styleMap) {
		String regExCss = "([^\\.^\\n^{\\*/}]*[\\.]+[^\\{]*)\\{([^\\}]*)\\}";
		Pattern patterCss = Pattern.compile(regExCss, Pattern.CASE_INSENSITIVE);

		Matcher matcherCss = patterCss.matcher(htmlUserCss);
		while (matcherCss.find()) {
			String cssName = matcherCss.group(1).trim();
			String cssValue = matcherCss.group(2).trim();
			addHtmlCssStyle(styleMap, cssName, cssValue);
		}
	}

	/**
	 * 
	 * @描述：从Html中解析出css的Class样式Map
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月24日下午7:23:59
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param html
	 * @return
	 */
	private static Map<String, String> parseHtmlStyle(String html) {
		// 定义style的正则表达式{或<style[^>]*?>[\\s\\S]*?<\\/style>
		String regExStyle = "<[\\s]*?style[^>]*?>([\\s\\S]*?)<[\\s]*?\\/[\\s]*?style[\\s]*?>";
		Pattern patterStyle = Pattern.compile(regExStyle,
				Pattern.CASE_INSENSITIVE);
		// 定义HTML的Style节点的样式正则表达式
		String regExCss = "([^\\.^\\n^{\\*/}]*[\\.][^\\{]*)\\{([^\\}]*)\\}";
		Pattern patterCss = Pattern.compile(regExCss, Pattern.CASE_INSENSITIVE);

		Matcher matcherStyle = patterStyle.matcher(html);
		Map<String, String> styleMap = new HashMap<String, String>();
		while (matcherStyle.find()) {
			String styleStr = matcherStyle.group(1);
			Matcher matcherCss = patterCss.matcher(styleStr);
			while (matcherCss.find()) {
				String cssName = matcherCss.group(1).trim();
				String cssValue = matcherCss.group(2).trim();
				addHtmlCssStyle(styleMap, cssName, cssValue);
			}
		}
		addHtmlUserCss(styleMap);
		return styleMap;
	}

	/**
	 * 
	 * @描述：解析Html标签中的classes属性
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月25日下午8:07:05
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param nodeHtml
	 * @return
	 */
	private static String[] parseHtmlClasses(String nodeHtml) {
		if (StringUtils.isNotEmpty(nodeHtml)) {
			String tagName = nodeHtml.trim().split(" ")[0].substring(1);
			if (tagName.endsWith(">")) {
				tagName = tagName.substring(0, tagName.length() - 1);
			}
			String classReg = "(<[^<]+class=\")([^\"]+)(\"[^>]*>)";
			String oldClass = nodeHtml.replaceAll(classReg, "$2");
			oldClass = oldClass.equals(nodeHtml) ? "" : oldClass.trim();

			String[] oldClasses = oldClass.split(" ");
			String[] classes = new String[oldClasses.length * 2 + 1];
			// 根据优先级从高到低
			for (int i = 0, iLen = oldClasses.length; i < iLen; i++) {
				if (StringUtils.isNotEmpty(oldClasses[i])) {
					classes[i] = (tagName + "." + oldClasses[i]);
					classes[i + iLen] = "." + oldClasses[i];
				}
			}
			classes[oldClasses.length * 2] = tagName;
			return classes;
		}
		return new String[] {};
	}

	/**
	 * 
	 * @描述：删除指定字符串之间的段落P节点
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月26日下午7:26:32
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param html
	 * @param startText
	 * @param endText
	 * @return
	 */
	public static String deleteHtmlPart(String html, String startText,
			String endText) {
		Pattern patterNode = Pattern.compile(
				"([^>]*)(<([a-z/][-a-z0-9_:.]*)[^>/]*(\\/*)>)([^<]*)",
				Pattern.CASE_INSENSITIVE);
		int startIndex = -1;
		int endIndex = -1;
		boolean isFindEnd = false;
		Stack<Integer> pTagStack = new Stack<Integer>();
		Matcher matcherNode = patterNode.matcher(html);
		while (matcherNode.find()) {
			String tagName = matcherNode.group(3);
			if ("body".equalsIgnoreCase(tagName)) {
				startIndex = matcherNode.end();
			} else if ("p".equalsIgnoreCase(tagName)) {
				pTagStack.push(matcherNode.start());
			} else if ("/p".equalsIgnoreCase(tagName)) {
				Integer index = pTagStack.pop();
				if (isFindEnd && pTagStack.isEmpty()) {
					endIndex = index;
					break;
				}

			}
			if (!isFindEnd) {
				isFindEnd = (matcherNode.group(5).indexOf(endText) > -1);
			}
		}
		if ((startIndex > -1) && (endIndex > -1)) {
			return new StringBuffer(html.substring(0, startIndex)).append(
					html.substring(endIndex)).toString();
		} else {
			return html;
		}
	}

	/**
	 * 
	 * @描述：用Class样式替换到标签style属性中
	 * @创建人:WuXinfeng
	 * @创建时间:2017年4月24日下午7:24:33
	 * @修改人:
	 * @修改时间:
	 * @修改描述:
	 * @param html
	 * @return
	 */
	public static String replaceHtmlStyle(String html) {
		String resultHtml = html;
		StringBuffer htmlBuffer = new StringBuffer();

		// 将CSS样式嵌入到Html标签的style属性中
		Map<String, String> styleMap = parseHtmlStyle(resultHtml);
		if ((styleMap != null) && (styleMap.size() > 0)) {
			// Style属性样式正则表达式
			Pattern patterStyle = Pattern.compile(
					"(<[^<]+style=\")([^\"]+)(\"[^>]*>)",
					Pattern.CASE_INSENSITIVE);
			// Html标签正则表达式
			Matcher matcherTag = Pattern.compile(
					"([^>]*)(<([a-z/][-a-z0-9_:.]*)[^>/]*(\\/*)>)([^<]*)",
					Pattern.CASE_INSENSITIVE).matcher(resultHtml);
			while (matcherTag.find()) {
				String nodeTag = matcherTag.group(3);
				String nodeTagHtml = matcherTag.group(2);
				String nodeText = HtmlUtils.htmlUnescape(matcherTag.group(5));
				if (StringUtils.isNotEmpty(nodeTag)
						&& (!nodeTag.startsWith("/"))) {
					// String[] classes = parseHtmlClasses(nodeTagHtml);
					String[] classes = "body".equalsIgnoreCase(nodeTag) ? new String[] {}
							: parseHtmlClasses(nodeTagHtml);
					if (classes.length > 0) {
						Matcher matcherStyle = patterStyle.matcher(nodeTagHtml);
						if (matcherStyle.find()) {
							String newStyle = parseCssStyle(
									matcherStyle.group(2), classes, styleMap);
							if (StringUtils.isNotEmpty(newStyle)) {
								nodeTagHtml = nodeTagHtml.replaceAll(
										"(style=\"[^\"]+\")", "style=\""
												+ newStyle + "\"");
							}
						} else {
							String newStyle = parseCssStyle(null, classes,
									styleMap);
							if (StringUtils.isNotEmpty(newStyle)) {
								nodeTagHtml = nodeTagHtml.replaceAll(
										"(class=\"[^\"]+\")", "$1 "
												+ "style=\"" + newStyle + "\"");
							}
						}
					}
				}
				if ("span".equalsIgnoreCase(nodeTag)) {
					nodeText = HtmlUtils.htmlUnescape(nodeText)
							.replace(" ", "&ensp;").replace(" ", "&ensp;");
				} else {
					nodeText = HtmlUtils.htmlUnescape(nodeText).replace(" ",
							"&ensp;");
				}
				// 解决格式乱码符号问题
				nodeText = nodeText.replace(new String(new byte[] { -30, -128,
						-117 }), "");
				matcherTag
						.appendReplacement(htmlBuffer, nodeTagHtml + nodeText);
			}
			resultHtml = htmlBuffer.toString();
			htmlBuffer.setLength(0);
		}
		return resultHtml;
	}

}
